Quelltext /~heha/hs/sht11.zip/8051-Firmware/SHT11 via 8051 auf 4-Zeilen-Display.a51

$nomod51
$nopaging
$title (SHT11 via 8051 auf 4-Zeilen-Display)
$include (80C515.mcu)
	DSEG AT 20h
;Für die Festkommazahlausgabe
Fix_Flags:	ds	1	;Steuerbits
Fix_Feldb:	ds	1	;Feldbreite in Zeichen
Fix_Dezim:	ds	1	;Dezimalstellen

	DSEG AT 30h
CurDisplay:	ds	1	;Für folgende Ausgabe aktive Display-Hälfte(n)
Num_Messung:	ds	1	;mein 8-bit-Zähler
Produkt:	ds	4	;das 16x16-Produkt
TMinMax:	ds	4	;minimale (LOW) und maximale (HIGH) Temperatur
FMinMax:	ds	4	;minimale (LOW) und maximale (HIGH) Feuchte
	CSEG AT RESET

;******************************************************************************
;** Wenn man beim Löten etwas Mist baut (hier: die Steuer- und Datenpins     **
;** unglücklich verteilt), kann man's auch durch Software wieder hinbiegen,  **
;** ist aber NICHT nachahmenswert!					     **
;** Verbleibenden Portpins werden rigoros auf den _gelesenen_ Pegel gesetzt, **
;** Vorsicht bei Eingängen!						     **
;******************************************************************************

DISP_DATA	set	P4	; Port mit den 4 Datenleitungen (Nibble-Modus)
DATA0_BIT	set	0
DATA1_BIT	set	2
DATA2_BIT	set	4
DATA3_BIT	set	6
DATA0		set	1 shl DATA0_BIT
DATA1		set	1 shl DATA1_BIT
DATA2		set	1 shl DATA2_BIT
DATA3		set	1 shl DATA3_BIT

DISP_CONTROL	set	P5	; Port mit den 4 Steuerleitungen
E_unten		set	1 shl 7		; 1=Enable untere 2 Zeilen
E_oben		set	1 shl 6		; 1=Enable obere 2 Zeilen
RW		set	1 shl 5		; 0=Schreiben, 1=lesen
RS		set	1 shl 4		; 0=Steuerbefehl, 1=Zeichen
Eu_BIT		set	DISP_CONTROL.7
Eo_BIT		set	DISP_CONTROL.6
RW_BIT		set	DISP_CONTROL.5
RS_BIT		set	DISP_CONTROL.4

SCK		set	P3.4			; für SHT11
DAT		set	P3.5			; für SHT11

	ljmp	init		;Reset-Vektor (keine Interrupts)
	
;******************************
;** Eine dumme Warteschleife **
;******************************
wait1:
;Wartet 1 Millisekunde
;PE: -
;PA: -
;VR: R5=0
	MOV     R5,#250
wait4xR5:
	NOP			;1	Wartet R5*4µs
	NOP			;1
	DJNZ    R5,wait4xR5	;2	;4µs*256=1ms
	ret
;wait1 ENDP

wait:
;Wartet <R4> Millisekunden
	call	wait1
	djnz	r4,wait
        RET                   

;*******************************
;** Anzeige: LowLevel-Zugriff **
;*******************************
;PUBLIC disp_addr_in, disp_data_in, disp_ctrl_out, disp_char_out, disp_init_ll

disp_nib_in:
;1 Nibble vom Display einlesen
;PE: [CurDisplay]=E_unten _oder_ E_oben, RW_BIT=1 und RS_BIT schon gesetzt
;PA: a=gelesenes Nibble, High-Teil=0
;VR: a
	mov	a,DISP_DATA
	orl	a,#(DATA3 or DATA2 or DATA1 or DATA0)
	mov	DISP_DATA,a	; alle Bits high = hochohmig
	mov	a,DISP_CONTROL
	orl	a,CurDisplay
	mov	DISP_CONTROL,a
	nop			;Zeit bis zum Erscheinen der Daten t(DDR)=360ns
	clr	a
	mov	c,DISP_DATA.DATA3_BIT
	rlc	a
	mov	c,DISP_DATA.DATA2_BIT
	rlc	a
	mov	c,DISP_DATA.DATA1_BIT
	rlc	a
	mov	c,DISP_DATA.DATA0_BIT
	rlc	a
disp_disable:
	clr	Eu_BIT
	clr	Eo_BIT
	ret

disp_data_in:	; Befehl "Read Data"
;PE: r2=E_oben _oder_ E_unten
;PA: a=gelesene Daten
;VR: a,b, RW_BIT=1, RS_BIT=1
	setb	RS_BIT
	sjmp	disp_byt_in
disp_addr_in:	; Befehl "Read Busy+Addr"
;PE: r2=E_oben _oder_ E_unten
;PA: a=gelesene Daten
;VR: a,b, RW_BIT=1, RS_BIT=0
	clr	RS_BIT
disp_byt_in:
;1 Byte vom Display einlesen
;PE: [CurDisplay] = E_oben _oder_ E_unten sowie RW=1 und RS wie gewünscht
;PA: a=gelesene Daten
;VR: a,r2
	setb	RW_BIT
	call	disp_nib_in	;High-Nibble zuerst lesen
	swap	a
	mov	r2,a
	call	disp_nib_in	;Low-Nibble danach lesen	
	orl	a,r2
	ret
	
disp_wait_ready:	;Wartet bis Display bereit zum Datenempfang
;VR: RW_BIT=1, RS_BIT=0, kann komplett blockieren!
	push	ACC
disp_warte:
	 call	disp_addr_in
	 jb	ACC.7,disp_warte
	pop	ACC
	ret

disp_char_out:
;1 Zeichen (mit RS=1) auf Display-Hälfte(n) ausgeben, wartet auf Bereitschaft
;PE: a=Zeichen (oder Zeile des Zeichenbildes) [CurDisplay]=Display-Hälften-Bit(s)
;PA: -
;VR: r2
	call	disp_wait_ready
	setb	RS_BIT
	sjmp	disp_byt_out
disp_ctrl_out:
;1 Steuer-Byte (mit RS=0) auf Display-Hälfte(n) ausgeben, wartet auf Bereitschaft
;PE: a=Steuerbyte, [CurDisplay]=Display-Hälften-Bit(s)
;PA: -
;VR: r2
	call	disp_wait_ready	;löscht RS bereits(!)
disp_byt_out:
;1 Byte auf Display ausgeben OHNE zu warten
;PE: a=Zeichen- oder Steuerbyte, RS_BIT nach Wunsch, [CurDisplay]=Bits
;PA: -
;VR: r2
	clr	RW_BIT		;immer "schreiben"
	acall	disp_nib_out
disp_nib_out:	;Ausgabe eines Nibbles <a> aufs Display(s) <r2> ohne auf Not-Busy warten
;PE: a=Zeichen- oder Steuer-Nibble IM HIGH-TEIL, r2="Steuerleitungen", also
;       E_oben = oberen Controller ansprechen, E_unten = entsprechend, auch beide gleichzeitig möglich
;	RS_BIT = Zeichenausgabe (sonst Steuerbefehl)
;PA: a: Low-Nibble zum High-Nibble geschafft, Low-Nibble undefiniert
;VR: a,r2
	rlc	a		;Bit ausschieben
	mov	DISP_DATA.DATA3_BIT,c	;Bit3 hier einsetzen
	rlc	a		;Bit ausschieben
	mov	DISP_DATA.DATA2_BIT,c	;Bit2 dort einsetzen
	rlc	a		;Bit ausschieben
	mov	DISP_DATA.DATA1_BIT,c	;dito
	rlc	a		;Bit ausschieben
	mov	DISP_DATA.DATA0_BIT,c
	mov	r2,a
	mov	a,DISP_CONTROL
	orl	a,CurDisplay
	mov	DISP_CONTROL,a	;das setzt die gewünschen Bits
	mov	a,r2
	jmp	disp_disable	;fallende Flanke(n) erzeugen

disp_init_ll:
;LowLevel-Initialisierung des Displays und seines Interfaces
;PE: -
;PA: [CurDisplay] adressiert noch beide Display-Hälften
;VR: a,r2,r4,r5
	mov	CurDisplay,#E_oben or E_unten	;beide Hälften
	clr	RS_BIT		;immer "Steuerbefehl"
	clr	RW_BIT		;immer "schreiben"
	mov	a,#30h
	call	disp_nib_out
	mov	r4,#4
	call	wait
	mov	a,#30h
	call	disp_nib_out
	call	wait1
	mov	a,#30h
	call	disp_nib_out
	call	wait1
	mov	a,#20h		; auf Nibble-Betrieb stellen
	call	disp_nib_out
	call	wait1
	mov	a,#28h		; "System Set": 2/4 Zeilen
	jmp	disp_ctrl_out

;********************************
;** Anzeige: HighLevel-Zugriff **
;********************************
;PUBLIC put_cg, gotoxy, put_xy, Put_Follow, Put_XY_Follow, disp_init

put_cg:	;Zeichen-Bitmap setzen
;PE: a=CG-Adresse (40h=1. Zeichen, 48h=2. Zeichen usw.)
;    r3=Anzahl Bytes
;    DPTR=Bitmap-Zeiger (ins Code-Segment) 8 Bytes
;PA: DPTR zeigt hinter die 8 Bytes
;VR: a,b,DPTR,r2,r3,[CurDisplay] (danach gotoxy aufrufen!)
	mov	CurDisplay,#E_oben or E_unten	;beide Chips
	call	disp_ctrl_out	; "CG-Adresse setzen"
pu_cg_next:
	clr	a
	movc	a,@a+dptr
	inc	dptr
	call	disp_char_out
	djnz	r3,pu_cg_next
	ret

gotoxy:	
;PE: R3=Spalte (Bits 0..5) und Zeile (Bits 6 und 7)
;PA: [CurDisplay]=Zeichen-Ausgabe-"Adresse" für folgende byt_out-Aufrufe
;VR: a,r2
	mov	CurDisplay,#E_oben
	mov	a,r3		;r3 legt fest E_oben oder E_unten mit Bit 7
	anl	a,#80h
	jz	pu_1		;E_oben oder E_unten?
	mov	CurDisplay,#E_unten
pu_1:	mov	a,r3
	orl	a,#80h		; Adress-Befehl zusammensetzen
	jmp	disp_ctrl_out	; "CC-Adresse setzen"
;gotoxy ENDP

put_xy:	;String-Ausgabe aus Codesegment
;PE: r3=Ausgabe-Adresse (0=1. Zeile, 40h=2. Zeile, 80h=3. Zeile, C0h=4. Zeile)
;    DPTR=String-Zeiger (im Code-Segment)
;PA: DPTR zeigt hinter die Null
;VR: a=0,DPTR,r2
	call	gotoxy
	sjmp	put_string
put_string_loop:
	call	disp_char_out
put_string:
	clr	a
	movc	a,@a+dptr
	inc	dptr
	jnz	put_string_loop		;(noch ein) Zeichen ausgeben
	ret

Put_Follow:
;Ausgabe konstanter ASCIIZ-String, der nach dem Unterprogramm-Aufruf
;notiert wird
;PE: - (CurDisplay muss durch einen Aufruf von gotoxy stehen)
;PA: -
;VR: a=0,dptr,r2
	pop	DPH
	pop	DPL
	call	put_string
	jmp	@a+dptr		;zurück zum Aufrufer (wirklich!)

Put_XY_Follow:
;wie "gotoxy" und "Put_Follow" zusammen
;PE: R3 = Position
;PA: -
;VR: a=0,dptr,r2
	pop	DPH
	pop	DPL
	call	put_xy
	jmp	@a+dptr		;zurück zum Aufrufer (wirklich!)
	
disp_init:
;HighLevel-Initialisierung: Modus setzen u.ä.
	mov	a,#08h
	call	disp_ctrl_out
	mov	a,#01h
	call	disp_ctrl_out
	mov	a,#06h
	call	disp_ctrl_out
	mov	a,#00001100b	;Cursors blinken usw.
	jmp	disp_ctrl_out	
	
;********************************************************
;** Anzeige: Anwendungs-orientierte Routinen und Daten **
;********************************************************

;Hallo2:	db	1,9,"  Tr",0E1h,"nen",0F5h,"berstr",0EFh,"mt ",0e4h,"F k",8,0
;Hallo3:	db	"µ@#+*'€^^ ",0

;ein paar "hübsche" (fehlende) Zeichen fürs Display
ZG0:	db	01110b		;SYMBOL großes Ohm
	db	10001b		; (das kleine sieht ja hässlich aus!)
	db	10001b
	db	10001b
	db	01010b
	db	01010b
	db	11011b
	db	00000b		;Cursorzeile

ZG1:	db	10001b		;LATIN1 großes Ä
	db	00100b
	db	01010b
	db	10001b
	db	11111b
	db	10001b
	db	10001b
	db	00000b		;Cursorzeile

ZG2:	db	10001b		;LATIN1 großes Ö
	db	01110b
	db	10001b
	db	10001b
	db	10001b
	db	10001b
	db	01110b
	db	00000b		;Cursorzeile

ZG3:	db	10001b		;LATIN1 großes Ü
	db	00000b		;(auch das kleine ü sieht blöd aus)
	db	10001b
	db	10001b
	db	10001b
	db	10001b
	db	01110b
	db	00000b		;Cursorzeile
	
ZG4:	db	00111b		;WIN1250 Euro-Symbol (hä?)
	db	01000b
	db	11111b
	db	10000b
	db	11110b
	db	10000b
	db	01110b
	db	00000b		;Cursorzeile

ZG5:	db	00000b		;ASCII Backslash \
	db	10000b
	db	01000b
	db	00100b
	db	00010b
	db	00001b
	db	00000b
	db	00000b		;Cursorzeile

ZG6:	db	00000b		;ASCII Schlange/Tilde ~
	db	00000b
	db	10110b
	db	01101b
	db	00000b
	db	00000b
	db	00000b
	db	00000b		;Cursorzeile
	
Prepare_Display:
	mov	r3,#0*64+0	;oben links
	call	Put_XY_Follow
	db	"Temperatur + Feuchtemessung",0
	;Spalte mit 3x "°C" ausgeben
	mov	r3,#1*64+13	;Zeile 1 = 2. Zeile
ph1:	call	Put_XY_Follow
	db	0DFh,"C",0
	mov	a,r3
	add	a,#1*64		;1 Zeile runter
	mov	r3,a
	jnc	ph1
	;Spalte mit 3x "%rF" ausgeben
	mov	r3,#1*64+24	;ganz hinten
ph2:	call	Put_XY_Follow
	db	"%rF",0
	mov	a,r3
	add	a,#1*64		;1 Zeile runter
	mov	r3,a
	jnc	ph2
	;"Min" und "Max" ausgeben
	mov	r3,#2*64+0
	call	Put_XY_Follow
	db	"Min:",0
	mov	r3,#3*64+0
	call	Put_XY_Follow
	db	"Max:",0
	ret

itoa:
;PE: r4=auszugebende 8-bit-Zahl
	mov	r3,#0
	mov	a,r4
itoa_1:	mov	B,#10
	div	ab
	push	B
	inc	r3
	jnz	itoa_1
itoa_2:
	pop	ACC
	add	a,#'0'
	call	disp_char_out
	djnz	r3,itoa_2
	ret
	
FixOut16:	;PROC
;Ausgabe einer 16-bit-Festkommazahl
;PE: r7:r6 = 16-bit-Zahl vzb.
;    Fix_Feldb = Feldbreite
;    Fix_Dezim  = Anzahl Dezimalstellen
;    Fix_Flags  = weitere Steuerbits... (???)
;PA: -
;VR: r3=0,r4,r5=0,r6=0,r7=0
	mov	a,r7
	rlc	a
	mov	Fix_Flags.7,c	;Vorzeichen-Merker
	jnc	do_6
	clr	c
	clr	a
	subb	a,r6		;Zweierkomplement
	mov	r6,a
	clr	a
	subb	a,r7
	mov	r7,a
do_6:	mov	r3,#0
do_3:	mov	r5,#16
	mov	r4,#0
do_2:	;Dividend R4:R7:R6 linksschieben
	mov	a,r6
	rlc	a
	mov	r6,a
	mov	a,r7
	rlc	a
	mov	r7,a
	mov	a,r4
	rlc	a
	mov	r4,a
	;Bedingte Subtraktion von 10 von R4
	add	a,#-10
	jnc	do_1
	mov	r4,a
do_1:	;cpl	c
	mov	a,r6	;CY ins Bit 0 setzen
	rr	a
	rlc	a
	mov	r6,a
	djnz	r5,do_2
	;nach der Division: R4 = Rest, R7:R6=Quotient
do_8:	push	AR4
	inc	r3
	mov	a,r3
	cjne	a,Fix_Dezim,do_7
	mov	r4,#'.'-'0'
	push	AR4	;Punkt einpushen
	inc	r3
do_7:	mov	a,r6
	orl	a,r7
	jnz	do_3
	mov	r4,#0
	mov	a,r3	;bspw. =3 bei 2 Dezimalstellen ist (noch) nicht OK
	dec	a
	setb	c
	subb	a,Fix_Dezim
	jc	do_8
	jnb	Fix_Flags.7,do_9
	mov	r4,#'-'-'0'
	push	AR4
	inc	r3
;ab hier wird gepoppt und ausgegeben	
do_9:	setb	c
	mov	a,Fix_Feldb
	subb	a,r3
	jc	do_4
	inc	a
	mov	r4,a
do_5:	mov	a,#' '
	call	disp_char_out	;führende Leerzeichen
	djnz	r4,do_5
do_4:
	pop	ACC
	add	a,#'0'
	call	disp_char_out
	djnz	r3,do_4
	ret
;DezOut16 ENDP

SaveFixOut16XY:
	call	gotoxy
SaveFixOut16:
	push	AR3
	push	AR6
	push	AR7
	 call	FixOut16
	pop	AR7
	pop	AR6
	pop	AR3
	ret
	
HexOut:	;PROC
;PE: A=auszugebende Hex-Zahl, R2 siehe nib_out
;PA: -
;VR: A
	push	ACC
	 swap	a
	 acall	NibOut	;vorwärts
	pop	ACC
NibOut:	;gibt Low-Nibble von A hexadezimal aus
	anl	a,#0Fh
	add	a,#90h
	da	a
	addc	a,#40h
	da	a	;auf wundersame Weise wird so aus 0..F ein '0'..'F'
	jmp	disp_char_out
;HexOut ENDP

Mul16x16: ;PROC
;PE: R5:R4 = Faktor 1 (vzl.)
;    R7:R6 = Faktor 2 (vzl.)
;PA: [Produkt] = Produkt
;VR: a,b
	;1.
	mov	a,r4
	mov	B,r6
	mul	ab
	mov	Produkt,a
	mov	Produkt+1,B
	;2.
	mov	a,r5
	mov	B,r7
	mul	ab
	mov	Produkt+2,a
	mov	Produkt+3,B
	;3.
	mov	a,r4
	mov	B,r7
	acall	mu2	;vorwärts: ASM51 macht nur 1 Pass
	mov	a,r5
	mov	B,r6
mu2:	mul	ab
	add	a,Produkt+1
	mov	Produkt+1,a
	mov	a,B
	addc	a,Produkt+2
	mov	Produkt+2,a
	jnc	mu1
	inc	Produkt+3
mu1:	ret
;Mul16x16 ENDP

;*******************
;** SHT11-Zugriff **
;*******************
SHT11_ConnReset:	;PROC
;Reset- und Startsequenz für SHT11 ausgeben --> muss das sein?? 
;PE: - (DATA=H, SCL=L)
;PA: - (DATA=H, SCL=L)
;VR: r5=0
;ALLE__ Zeiten sind evtl viel zu lang!
	mov	r5,#10
	setb	DAT
abcd:	
	setb	SCK
	setb	DAT
	nop
	clr	SCK
	setb	DAT
	nop
	djnz	r5,abcd
SHT11_Start:
	setb	SCK
	nop
	nop
	clr	DAT
	nop
	nop
	clr	SCK
	nop
	nop
	setb	SCK
	nop
	nop
	setb	DAT
	nop
	nop
	clr	SCK		;Ende SHT_Start
	ret
;SHT11_ConnReset ENDP
	
SHT11_ByteOut:	;PROC
;(Kommando-) Byte ausgeben und Acknowledge abholen
;PE: A=Kommando-Byte (DATA=H, SCL=L)
;PA: CY=1 wenn Fehler, CY=0 wenn Ack-Bit OK (DATA=H, SCL=L)
;VR: R5=0,a
  ;Zähler mit 8 Laden
	mov	r5,#8
SHT11_ByteOut_Loop:
	rlc	a	;Bits ausschieben
	mov	DAT,c	;Datenbit setzen oder rücksetzen
	setb	SCK	;Takt=H
	nop
	clr	SCK	;Takt=L
	setb	DAT
	djnz	r5,SHT11_ByteOut_Loop
;SHT11ack:
	setb	SCK
	nop	
	mov	C,DAT
	;!!!!!!!!Wenn SHT11_DATA = 1 wird, alles ok!
	clr	SCK
	setb	DAT
	ret
;SHT11_ByteOut ENDP

SHT11_ByteIn: ;PROC
;PE: a=0: weiteres Byte anfordern (Bit 0)
;    a=1: kein weiteres Byte anfordern
;PA: a=gelesenes Byte
	mov	r5,#8	
SHT11_ByteIn_Loop:
	setb	SCK
	setb	DAT
	nop
	nop
	mov	c,DAT
	rlc	a
	clr	SCK
	setb	DAT
	djnz	r5,SHT11_ByteIn_Loop
	;Quittungsbit
	mov	DAT,c	;aus A gekommen
	setb	SCK
	nop
	nop
	clr	SCK
	setb	DAT
	ret
;SHT11_ByteIn ENDP

SHT11_Get_Messwert: ;proc
;PE: r6=5 für %rF, =3 für Temperatur
;PA: r7:r6=Messwert vom SHT11
;    CY=1 wenn kein Messwert lieferbar
;VR: r7,r6,r4,r5=0,a
	call	SHT11_Start
	mov	a,r6
	call	SHT11_ByteOut
	jc	SHT11_raus
	mov	r4,#0		;256 ms warten
	call	wait
	setb	C
	jb	DAT,SHT11_raus	;wenn SHT11 immer noch nicht fertig
	clr	a	;weitere Daten anfordern
	call	SHT11_ByteIn
	mov	r7,a	;High-Byte %rF
	mov	a,#1	;keine weiteren Daten (Prüfsumme) anfordern
	call	SHT11_ByteIn
	mov	r6,a	;Low-Byte %rF
	clr	C
SHT11_raus:
	ret
;SHT11_Get_Messwert endp

Calc_Feuchte: ;PROC
;PE: R7:R6=Wert vom Sensor ("SO(RH)")
;PA: R7:R6=Feuchte in Hundertstel Prozent (Festkomma)
;VR: R4,R5
	push	AR2
	push	AR3
	 ;linearer Summand
	 mov	r4,#LOW(1037)	;LOW(4.05*256)
	 mov	r5,#HIGH(1037)
	 call	Mul16x16
	 mov	r2,Produkt+1		;"mittlerer" Teil, entspr. /256
	 mov	r3,Produkt+2
	 ;quadratischer Summand
	 mov	r4,6
	 mov	r5,7
	 call	Mul16x16		;Quadrat
	 mov	r4,#LOW(4698)		;0.07168*64K
	 mov	r5,#HIGH(4698)
	 mov	r6,Produkt+1		;"mittlerer" Teil, /256
	 mov	r7,Produkt+2
	 call	Mul16x16
	 ;subtrahieren
	 clr	c
	 mov	a,r2
	 subb	a,Produkt+2		;"oberer" Teil, /64K
	 mov	r2,a
	 mov	a,r3
	 subb	a,Produkt+3
	 mov	r3,a
	 ;konstanter Summand
	 mov	a,r2
	 add	a,#LOW(-400)
	 mov	r6,a
	 mov	a,r3
	 addc	a,#HIGH(-400)
	 mov	r7,a
	pop	AR3
	pop	AR2
	ret
;Calc_Feuchte ENDP

InitAllMinMax:	
;initialisiert TMinMax und FMinMax (aufeinanderfolgend!)
;PE: - PA: - VR: R0
	mov	r0,#TMinMax
	call	InitMinMax
InitMinMax:	
;initialisiert zwei aufeinanderfolgende WORDs mit MAXINT und -MAXINT
	mov	@r0,#0FFh
	inc	r0
	mov	@r0,#07Fh
	inc	r0
	mov	@r0,#000h
	inc	r0
	mov	@r0,#080h
	inc	r0
	ret

MakeMinMax:
;Berechnet neue Minima und Maxima und gibt diese bei Veränderung aus
;PE: R3 = Cursor-Spalte (Bit 5:0), Zeile=1
;    R7:R6 = aktueller Messwert
;    R0 = Zeiger auf Minimum-WORD (LOW) und Maximum-WORD (HIGH), d.h.
;	[R0]=LOW Minimum, [R0+1]=HIGH Minimum, [R0+2]=LOW Maximum usw.
;PA: -
;VR: R0,R2,R3
	clr	c
	mov	a,r6
	subb	a,@r0
	inc	r0
	mov	a,r7
	subb	a,@r0
	jnb	OV,mmm1	;=OV	
	cpl	a
mmm1:	jnb	ACC.7,NoNewMin
	mov	a,r7
	mov	@r0,a
	dec	r0
	mov	a,r6
	mov	@r0,a
	inc	r0
	mov	a,r3
	anl	a,#03Fh		;Spalte stehen lassen
	orl	a,#2*64		;Zeile 2
	mov	r3,a
	call	SaveFixOut16XY
NoNewMin:
	inc	r0	;jetzt zeigt R0 aufs Maximum
	clr	c
	mov	a,@r0
	subb	a,r6
	inc	r0
	mov	a,@r0
	subb	a,r7
	swap	a		;sprungfreie Version, genauso lang
	rr	a
	xrl	a,PSW
	jnb	ACC.2,NoNewMax
	mov	a,r7
	mov	@r0,a
	dec	r0
	mov	a,r6
	mov	@r0,a
	mov	a,r3
	anl	a,#03Fh		;Spalte stehen lassen
	orl	a,#3*64		;Zeile 3
	mov	r3,a
	call	SaveFixOut16XY
NoNewMax:	
	ret

NoFixOutXY:
;Ausgabe KEINER Zahl bei Interface-Problem mit dem SHT11
	call	Put_XY_Follow
	db	" ---.--",0
	ret
	
init:
	mov	SP,#07Fh
	call	disp_init_ll	;LowLevel-Initialisierung
	call	disp_init	;HighLevel-Init.

	mov	DPTR,#ZG0	;großes Ohm, Ä, Ö, Ü, Euro, \, ~
	mov	a,#40h		;Adress-Befehl: Adresse 0
	mov	r3,#8*7		;7 aufeinanderfolgende Zeichen
	call	put_cg
	call	Prepare_Display

	mov	Fix_Feldb,#7
	mov	Fix_Dezim,#2
	mov	Num_Messung,#0
	call	InitAllMinMax

MainLoop:
	mov	r3,#1*64+1
	call	gotoxy
	inc	Num_Messung
	mov	a,Num_Messung
	call	HexOut
	;Temperatur einlesen, umrechnen und ausgeben
	mov	r6,#00000011b		;Kommando: Temperatur
	call	SHT11_Get_Messwert
	mov	r3,#1*64+5
	jc	NoTemp
	mov	a,r6
	add	a,#LOW(-4000)
	mov	r6,a
	mov	a,r7
	addc	a,#HIGH(-4000)
	mov	r7,a
	call	SaveFixOut16XY
	mov	r0,#TMinMax
	call	MakeMinMax	;übernimmt auch R3
	sjmp	TempOK
NoTemp:	call	NoFixOutXY
TempOK:	;Feuchte einlesen, umrechnen und ausgeben
	mov	r6,#00000101b		;Kommando: %rF
	call	SHT11_Get_Messwert
	mov	r3,#1*64+16
	jc	NoHumi
	call	Calc_Feuchte		;"umrechnen" in Prozent
	call	SaveFixOut16XY
	mov	r0,#FMinMax
	call	MakeMinMax	;übernimmt auch R3
	sjmp	HumiOK
NoHumi:	call	NoFixOutXY
HumiOK:
	mov	r4,#0
	call	wait		;256 ms (Maximum) verbraten
	mov	P1,#128
	mov	a,P6		;P6 ist leider nicht bitadressierbar
	jb	ACC.0,MainLoop
	call	InitAllMinMax	;mit der Taste an P6.0 Minima/Maxima rücksetzen
	sjmp	MainLoop
END
Vorgefundene Kodierung: UTF-80